package cn.lyjuan.first.netty._4_netty_serialize.msg.codec;

import cn.lyjuan.base.util.HexUtils;
import cn.lyjuan.base.util.StringUtils;
import cn.lyjuan.first.netty._4_netty_serialize.cst.MessageConst;
import cn.lyjuan.first.netty._4_netty_serialize.msg.MyMessage;
import cn.lyjuan.first.netty._4_netty_serialize.msg.reader.IReader;
import cn.lyjuan.first.netty._4_netty_serialize.msg.reader.ReaderFactory;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageCodec;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import java.util.List;

public class MessageCodec extends ByteToMessageCodec<MyMessage>
{
    private static Logger log = LogManager.getLogger(MessageCodec.class);

    private ReaderFactory readerFactory;

    @Override
    protected void encode(ChannelHandlerContext ctx, MyMessage msg, ByteBuf out) throws Exception
    {
        String str = msg.getHead() + msg.getData() + msg.getFoot();
//        out.writeBytes(HexUtils.fromHex(str));
        out.writeBytes(HexUtils.fromHex(msg.getHead()));
        out.writeBytes(msg.getData().getBytes(MessageConst.CHARSET));
        out.writeBytes(HexUtils.fromHex(msg.getFoot()));

        log.debug("encode: " + msg);
    }

    @Override
    protected void decode(ChannelHandlerContext ctx, ByteBuf buf, List<Object> out) throws Exception
    {
        if (null == buf || buf.readableBytes() < MessageConst.LEN_PKG_MIN) return;

        // 读取消息
        readPkges(buf, out, MessageConst.READ_TRY_COUNT);
    }

    private void readPkges(ByteBuf buf, List<Object> out, int tryCount)
    {
        try
        {
            while (true)
            {
                MyMessage msg = readPkg(buf);

                if (null == msg) break;// 没有更多完整的消息

                out.add(msg);
            }
        } catch (Throwable t)
        {
            log.error("decode error", t);
            if (--tryCount > 0)
                readPkges(buf, out, tryCount);
            else
                // todo 异常处理
                throw new RuntimeException(t);
        }
    }

    private MyMessage readPkg(ByteBuf buf)
    {
        int readerIndex = buf.readerIndex();// 保存读取位置
        if (buf.readableBytes() < MessageConst.LEN_PKG_MIN) return null;// 剩余可读取数据小于最小包长

        byte[] b = null;

        // 头部
        b = new byte[MessageConst.LEN_HEAD];
        buf.readBytes(b);
        String head = HexUtils.toHex(b);

        // 数据
        IReader reader = readerFactory.dispatchReader(head);
        String data = reader.read(buf);
        if (null == data)// 为null表示数据不完整，继承等待
        {
            buf.readerIndex(readerIndex);// 恢复读取位置
            return null;
        }

        // 尾部
        String foot = null;
        if (buf.readableBytes() >= MessageConst.LEN_FOOT)
        {
            b = new byte[MessageConst.LEN_FOOT];
            buf.readBytes(b);
            foot = HexUtils.toHex(b);
        }

        // 生成mymessage
        MyMessage msg = new MyMessage(head, data, foot);

        return msg;
    }

    public ReaderFactory getReaderFactory()
    {
        return readerFactory;
    }

    public MessageCodec setReaderFactory(ReaderFactory readerFactory)
    {
        this.readerFactory = readerFactory;
        return this;
    }
}
